export function serializeJsonToUrlQuery(json) {
    if (!json) {
        return "";
    }
    let params = [];
    Object.keys(json).forEach(key => {
        let value = json[key];
        params.push(...serializeUrlQuery(key, value));
    });
    return params.join("&");
}

export function serializeFormDataToUrlQuery(formData) {
    if (!formData) {
        return "";
    }
    let params = [];
    formData.forEach((value, key) => {
        params.push(...serializeUrlQuery(key, value));
    });
    return params.join("&");
}

function serializeUrlQuery(name, value) {
    let params = [];
    if (typeof value !== "undefined" && value !== null) {
        name = encodeURIComponent(name);
        if (value instanceof Date) {
            params.push(name + "=" + encodeURIComponent(value.getTime()));
        } else if (value instanceof Array) {
            value.forEach(element => {
                if (typeof element === "undefined" || element === null) {
                    params.push(name + "=");
                } else if (element instanceof Date) {
                    params.push(name + "=" + encodeURIComponent(element.getTime()));
                } else {
                    params.push(name + "=" + encodeURIComponent(element));
                }
            });
        } else {
            params.push(name + "=" + encodeURIComponent(value));
        }
    }
    return params;
}

export const RETURN_TYPE = {
    TEXT: "TEXT",
    JSON: "JSON",
    RESPONSE: "RESPONSE"
};

export const SUBMIT_TYPE = {
    FORM_DATA: "FORM_DATA",
    URL_ENCODED: "URL_ENCODED",
    JSON: "JSON"
};

export function doFetch({
                            url = "",
                            method = "GET",
                            timeout = 0,
                            urlParams,
                            bodyParams,
                            headers,
                            submitType = SUBMIT_TYPE.URL_ENCODED,
                            returnType = RETURN_TYPE.TEXT,
                            credentials = 'same-origin',
                            mode = 'same-origin'
                        }) {
    if (urlParams) {
        let query = serializeJsonToUrlQuery(urlParams);
        if (url.lastIndexOf("?") === -1) {
            url = url + "?" + query;
        } else {
            url = url + "&" + query;
        }
    }

    const options = {
        method: method,
        headers: {}
    };
    if (headers) {
        options.headers = {...headers};
    }

    options.headers['X-Requested-With'] = 'FetchRequest';
    options.credentials = credentials;
    options.mode = mode;

    switch (submitType) {
        case SUBMIT_TYPE.FORM_DATA:
            options.headers = {
                ...options.headers
            };
            if (bodyParams) {
                options.body = bodyParams;
            }
            break;
        case SUBMIT_TYPE.URL_ENCODED:
            options.headers = {
                ...options.headers,
                ...{"Content-Type": "application/x-www-form-urlencoded"}
            };
            if (bodyParams) {
                if (bodyParams instanceof FormData) {
                    options.body = serializeFormDataToUrlQuery(bodyParams);
                } else {
                    options.body = serializeJsonToUrlQuery(bodyParams);
                }
            }
            break;
        case SUBMIT_TYPE.JSON:
            options.headers = {
                ...options.headers,
                ...{"Content-Type": "application/json;charset=UTF-8"}
            };
            if (bodyParams) {
                options.body = JSON.stringify(bodyParams);
            }
            break;
        default:
            break;
    }
    console.debug("---request begin---");
    console.debug({url, ...options});
    return new Promise((resolve, reject) => {
        let promise;
        let timer;
        if (timeout && timeout > 0) {
            promise = Promise.race([
                fetch(url, options),
                new Promise((res, rej) => {
                    timer = setTimeout(() => {
                        rej({code: -1, msg: "访问超时"});
                    }, timeout);
                })
            ]);
        } else {
            promise = fetch(url, options);
        }
        promise
            .then(
                response => {
                    if (timer) {
                        clearTimeout(timer);
                    }
                    let {status} = response;
                    if (status !== 200) {
                        throw {message: `服务器返回错误状态：${status} ！`};
                    }
                    if (returnType === RETURN_TYPE.TEXT || returnType === RETURN_TYPE.JSON) {
                        return response.text();
                    } else {
                        return response;
                    }
                },
                error => {
                    if (timer) {
                        clearTimeout(timer);
                    }
                    reject(error);
                }
            )
            .then(data => {
                if (returnType === RETURN_TYPE.JSON) {
                    try {
                        let bodyJson = JSON.parse(data);
                        console.debug(bodyJson);
                        console.debug("---request end---");
                        resolve(bodyJson);
                    } catch (e) {
                        console.error(e);
                        console.debug("---request end---");
                        reject({code: -1, msg: '返回JSON格式错误', data});
                    }
                    return;
                }
                console.debug(data);
                console.debug("---request end---");
                resolve(data);
            })
            .catch(error => {
                if (timer) {
                    clearTimeout(timer);
                }
                console.debug("---request end---");
                reject({code: -1, error: error, msg: error.message});
            });
    });
}
